﻿using System;
using System.Collections;
using System.Collections.Generic;

using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Converts.Core;
using zijian666.Converts.Extensions;

namespace zijian666.Converts.Convertor;

/// <summary>
/// <seealso cref="IList{T}"/> 泛型集合转换器
/// </summary>
/// <typeparam name="TList">实现了 <seealso cref="IList{T}"/> 的类型</typeparam>
/// <typeparam name="TValue">集合元素的类型</typeparam>
public class ListConvertor<TList, TValue> : AllowNullConvertor<TList>, IFrom<string, TList?>, IFrom<object, TList?>, IFrom<object[], TList?>
    where TList : IList<TValue?>
{
    /// <summary>
    /// 转换器有错误
    /// </summary>
    private readonly bool _error;

/// <summary>
/// 构造函数
/// </summary>
/// <exception cref="ArgumentException"></exception>
    public ListConvertor() => _error = OutputType.MatchType(typeof(List<TValue>), typeof(IList<TValue>)) is not MacthedType.Equals and not MacthedType.Acceptable and not MacthedType.TryCreate;

    /// <inheritdoc />
    public ConvertResult<TList?> From(IConvertContext context, string input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (string.IsNullOrEmpty(input))
        {
            return context.Settings.CreateInstance<TList>();
        }

        var arr = context.Settings.Split(input);
        if (arr is TList result)
        {
            return result;
        }
        return From(context, (object)arr);
    }

    /// <summary>
    /// 创建实例对象
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    private TList CreateInstance(IConvertContext context)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        return OutputType.IsInterface
            ? (TList)context.Settings.CreateInstance(typeof(List<TValue>))
            : Activator.CreateInstance<TList>();
    }

    /// <inheritdoc />
    public ConvertResult<TList?> From(IConvertContext context, object input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (_error)
        {
            return ExceptionHelper.InstantiationFail(TypeFriendlyName, context.Settings.CultureInfo);
        }
        var enumerator = new KeyValueEnumerator<object, TValue>(context, input);

        if (enumerator.NotEnumerator)
        {
            var result = context.Convert<TValue>(input);
            if (result.Success)
            {
                var list1 = CreateInstance(context);
                list1.Add(result.Value);
                return list1;
            }
            return context.ConvertFail(this, input);
        }

        var list = CreateInstance(context);
        while (enumerator.MoveNext())
        {
            var result = enumerator.GetValue();
            if (!result.Success)
            {
                return ExceptionHelper.CollectionAddFail(TypeFriendlyName, list.Count + "", enumerator.OriginalValue, context.Settings.CultureInfo);
            }
            list.Add(result.Value);
        }
        return list;
    }

    /// <inheritdoc />
    public ConvertResult<TList?> From(IConvertContext context, object[] input)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (input is null)
        {
            throw new ArgumentNullException(nameof(input));
        }

        return From(context, input.GetEnumerator());
    }
}
